package com.pandora.credit.service.impl;

import com.pandora.common.util.*;
import com.pandora.credit.dto.request.SmsCodeRequest;
import com.pandora.credit.dto.response.AuthorizationTokenResponse;
import com.pandora.credit.entity.Customer;
import com.pandora.credit.exception.*;
import com.pandora.credit.exception.customer.CustomerAlreadyExistsException;
import com.pandora.credit.exception.customer.CustomerNotExistsException;
import com.pandora.credit.exception.sms.*;
import com.pandora.credit.service.CustomerService;
import com.pandora.credit.service.SmsServcie;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author developer
 */
@Service
public class SmsServiceImpl implements SmsServcie {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private CustomerService customerService;

    private Customer checkRequest(SmsCodeRequest req) {
        if (req == null) {
            logger.error("Empty request for sms_code");
            throw new EmptyRequestException();
        }

        //处理参数
        Integer type = req.getType();
        String mobile = req.getMobile();
        String smsCode = req.getCode();
        boolean flg = type == null || (type != Constants.SMS_CODE_TYPE_REGISTER && type != Constants.SMS_CODE_TYPE_FIND_PASSWORD);
        if (flg) {
            throw new ParameterErrorException();
        }
        if (VerifyUtil.isEmpty(mobile) || !RegexUtil.isMobile(mobile)) {
            throw new MobileNoInvalidException();
        }
        logger.info("mobile: {}, sms_code: {}", mobile, smsCode);
        Customer cus = customerService.getByMobile(mobile);
        if (type == Constants.SMS_CODE_TYPE_REGISTER
                && cus != null
                && cus.getStatus() > Constants.CUSTOMER_STATUS_TEMPORARY) {
            throw new CustomerAlreadyExistsException();
        }
        if (type == Constants.SMS_CODE_TYPE_FIND_PASSWORD && cus == null) {
            throw new CustomerNotExistsException();
        }
        return cus;
    }

    private AuthorizationTokenResponse validateSmsCode(SmsCodeRequest req, Customer cus) {
        String mobile = req.getMobile();
        String smsCode = req.getCode();
        String source = req.getSource();
        String memorySms = JedisUtil.get(Constants.BUSINESS_REDIS_URL,
                StringUtils.getStrParam(Constants.PC_BUSINESS_SMS, mobile));
        if (!VerifyUtil.isEmpty(memorySms) && memorySms.equals(smsCode)) {
            if (cus == null) {
                cus = new Customer();
                cus.setId(System.currentTimeMillis() * 1000);
                cus.setMobile(mobile);
                cus.setStatus(Constants.CUSTOMER_STATUS_TEMPORARY);
                cus.setSource(source);
                cus.setCreateTime(DateUtil.getNowTimestamp());
                cus.setUpdateTime(DateUtil.getNowTimestamp());
                customerService.save(cus);
            }
            String token = JedisUtil.get(Constants.BUSINESS_REDIS_URL,
                    StringUtils.getStrParam(Constants.MOBILE_AUTHORIZATION_TOKEN_KEY, mobile));
            if (VerifyUtil.isEmpty(token)) {
                token = StringUtils.encoderByMd5(String.valueOf(System.currentTimeMillis() * 1000));
                JedisUtil.set(Constants.BUSINESS_REDIS_URL,
                        StringUtils.getStrParam(Constants.MOBILE_AUTHORIZATION_TOKEN_KEY, mobile),
                        token,
                        Constants.AUTHORIZATION_TOKEN_EXPIRATION);
                JedisUtil.set(Constants.BUSINESS_REDIS_URL,
                        StringUtils.getStrParam(Constants.AUTHORIZATION_TOKEN_KEY, token),
                        mobile,
                        Constants.AUTHORIZATION_TOKEN_EXPIRATION);
            }
            return new AuthorizationTokenResponse(cus, token);
        } else {
            String smsCount = JedisUtil.get(Constants.BUSINESS_REDIS_URL,
                    StringUtils.getStrParam(Constants.MOBILE_SMS_COUNT_KEY, mobile));
            JedisUtil.set(Constants.BUSINESS_REDIS_URL,
                    StringUtils.getStrParam(Constants.MOBILE_SMS_COUNT_KEY, mobile),
                    String.valueOf(Integer.parseInt(smsCount) + 1),
                    Constants.EXPIRATION_TIME_OUT);
            throw new SmsCodeWrongErrorException();
        }
    }

    private Object sendSms(SmsCodeRequest req, String accessToken) {
        String mobile = req.getMobile();
        String captcha = req.getCaptcha();
        String sendAlready = JedisUtil.get(Constants.BUSINESS_REDIS_URL,
                StringUtils.getStrParam(Constants.PC_BUSINESS_SMS, mobile));
        if (!VerifyUtil.isEmpty(sendAlready)) {
            throw new SmsCodeAlreadySendException();
        }
        String mobileSmsCount = JedisUtil.get(Constants.BUSINESS_REDIS_URL,
                StringUtils.getStrParam(Constants.MOBILE_SMS_COUNT_KEY, mobile));
        if (!VerifyUtil.isEmpty(mobileSmsCount) && Integer.parseInt(mobileSmsCount) >= MagicConst.NUM_3) {
            if (!VerifyUtil.isEmpty(captcha)) {
                String captchaCode = JedisUtil.get(Constants.BUSINESS_REDIS_URL,
                        StringUtils.getStrParam(Constants.MOBILE_CAPTCHA_KEY, accessToken));
                if (!VerifyUtil.isEmpty(captchaCode)) {
                    logger.debug("mobile: {}, input captcha: {}, captcha: {}",
                            mobile, captcha.toLowerCase(), captchaCode.toLowerCase());
                    if (!(captcha.toLowerCase()).equals(captchaCode.toLowerCase())) {
                        throw new CaptchaCodeErrorException();
                    }
                } else {
                    throw new CaptchaCodeErrorTimeOutException();
                }
            } else {
                throw new RequiresCaptchaException();
            }
        }
        int validateSmsCode = StringUtils.random(1000, 9999);
        String content = StringUtils.getStrParam(Constants.SMS_TEMPLATE, String.valueOf(validateSmsCode));
        JedisUtil.set(Constants.BUSINESS_REDIS_URL,
                StringUtils.getStrParam(Constants.PC_BUSINESS_SMS, mobile),
                String.valueOf(validateSmsCode),
                Constants.SMS_EXPIRATION_TIME);
        boolean sendSms = VerifyUtil.smsSend(mobile, content);
        if (!sendSms) {
            throw new SmsCodeSendErrorException();
        }
        if (!VerifyUtil.isEmpty(mobileSmsCount)) {
            JedisUtil.set(Constants.BUSINESS_REDIS_URL,
                    StringUtils.getStrParam(Constants.MOBILE_SMS_COUNT_KEY, mobile),
                    String.valueOf(Integer.parseInt(mobileSmsCount) + 1),
                    Constants.EXPIRATION_TIME_OUT);
        } else {
            int count = 1;
            JedisUtil.set(Constants.BUSINESS_REDIS_URL,
                    StringUtils.getStrParam(Constants.MOBILE_SMS_COUNT_KEY, mobile),
                    String.valueOf(count),
                    Constants.EXPIRATION_TIME_OUT);
        }
        return null;
    }

    @Override
    public Object handleRequest(SmsCodeRequest req, String accessToken) {
        Customer cus = checkRequest(req);
        logger.info("type:{}", req.getType());

        //验证
        if (StringUtils.isNotEmpty(req.getCode())) {
            return validateSmsCode(req, cus);
        } else {
            return sendSms(req, accessToken);
        }
    }
}
